package com.gitee.deament.server.core.cli.db.set;

import cn.hutool.core.util.NumberUtil;
import com.gitee.deament.server.config.SystemConfig;
import com.gitee.deament.server.core.annotation.CliHander;
import com.gitee.deament.server.core.cli.AbstractCli;
import com.gitee.deament.server.core.data.ConnectData;
import com.gitee.deament.server.core.data.DBData;
import com.gitee.deament.server.core.data.datatype.Value;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * SRANDMEMBER key [count]
 * 可用版本： >= 1.0.0
 * 时间复杂度: 只提供 key 参数时为 O(1) 。如果提供了 count 参数，那么为 O(N) ，N 为返回数组的元素个数。
 * 如果命令执行时，只提供了 key 参数，那么返回集合中的一个随机元素。
 *
 * 从 Redis 2.6 版本开始， SRANDMEMBER 命令接受可选的 count 参数：
 *
 * 如果 count 为正数，且小于集合基数，那么命令返回一个包含 count 个元素的数组，数组中的元素各不相同。如果 count 大于等于集合基数，那么返回整个集合。
 *
 * 如果 count 为负数，那么命令返回一个数组，数组中的元素可能会重复出现多次，而数组的长度为 count 的绝对值。
 *
 * 该操作和 SPOP key 相似，但 SPOP key 将随机元素从集合中移除并返回，而 SRANDMEMBER 则仅仅返回随机元素，而不对集合进行任何改动。
 *
 * 返回值
 * 只提供 key 参数时，返回一个元素；如果集合为空，返回 nil 。 如果提供了 count 参数，那么返回一个数组；如果集合为空，返回空数组。
 * @author deament
 *
 */
@CliHander(command = "SRANDMEMBER")
public class SRANDMEMBERcli extends AbstractCli {
    @Override
    public void executeCli(ChannelHandlerContext channelHandlerContext, String command) {

            List<String> cliValues = getValues(command);
            if (cliValues.size() !=2 ||cliValues.size() !=3) {
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR wrong number of arguments for 'SRANDMEMBER' command"));
                return;
            }
            int db = ConnectData.SELECT_DB_STORAGE.getUseDB(channelHandlerContext.channel().id().asLongText());
            DBData dbData = SystemConfig.dbData;
            String key = cliValues.get(1);

            int count=1;
            if(cliValues.size()==3){
                if(!NumberUtil.isInteger(cliValues.get(2))){
                    count=Integer.parseInt(cliValues.get(2));
                    if(count==0){
                        channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(""));
                        return  ;
                    }
                }
            }
            try {
                Value<Set<String>> set = dbData.getSet(db, key);
                if (set == null || set.getValue().size() == 0) {
                    channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("nil"));
                    return;
                }
                if(count>0){
                    Iterator<String> iterator = set.getValue().iterator();
                    int outputCount=0;
                    StringBuilder output= new StringBuilder();
                    while (iterator.hasNext()&& outputCount<=count) {
                        String next = iterator.next();
                        output.append(next +"\r\n");

                        outputCount++;
                    }
                    channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(output.toString()));
                    return;
                }
                if(count<0){

                    int outputCount=0;
                    StringBuilder output= new StringBuilder();
                    while ( outputCount<= Math.abs(count)) {
                        Iterator<String> iterator = set.getValue().iterator();
                        String next = iterator.next();
                        output.append(next +"\r\n");
                        outputCount++;
                    }
                    channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(output.toString()));
                    return;
                }




            } catch (Exception e) {
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(e.getMessage()));
            }
    }
}
